package com.itheima.reggie.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.entity.PageParam;
import com.itheima.reggie.exception.CustomException;
import com.itheima.reggie.mapper.DishMapper;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.DishFlavorService;
import com.itheima.reggie.service.DishService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Transactional
public class DishServiceImpl implements DishService {
    
    @Autowired
    private DishMapper mapper;
    
    @Autowired
    private DishFlavorService dishFlavorService;
    
    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedisTemplate redisTemplate;
    
    
    //根据分类id，获取菜品数据
    @Override
    public List<DishDto> findByCategoryId(long categoryId , Integer status) {

        String key = "dish_"+categoryId+"_"+status;

        //从缓存获取数据 没有则查询数据库
        String data = (String) redisTemplate.opsForValue().get(key);
        if (data != null) {
            return JSON.parseObject(data, List.class);
        }

        //1. 构建条件对象
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();
        qw.eq(Dish::getCategoryId , categoryId);
        qw.eq(status != null , Dish::getStatus , status);
    
        //2. 执行查询
        List<Dish> dishList = mapper.selectList(qw);
        
        //3. 由于菜品里面没有口味数据，所以要遍历他们，然后给每一个菜品都找一找它自己的口味数据，然后构建出来DishDto，装到
        // 集合里面返回
        List<DishDto> dishDtoList = dishList.stream().map(dish -> {
            
            //3.1 遍历一次，就创建一个DishDto
            DishDto  dto = new DishDto();
            
            //3.2 把dish的数据拷贝到dto身上
            BeanUtils.copyProperties(dish , dto);
            
            //3.3 设置口味数据
            dto.setFlavors(dishFlavorService.findByDishId(dish.getId()));
            
            //3.4 返回dto
            return dto;
        }).collect(Collectors.toList());

        redisTemplate.opsForValue().set(key, JSON.toJSONString(dishDtoList));
        
        return dishDtoList;
    }
    
    //更新菜品
    @Override
    public int update(DishDto dishDto) {

        //redis查询数据
        Dish dishRedis = mapper.selectById(dishDto.getId());

        //1. 更新菜品表
        int row = mapper.updateById(dishDto);
        
        //2. 更新口味表
        //2.1 删除口味数据
        dishFlavorService.delete(dishDto.getId());
        
        //2.2 执行口味的添加
        int row2 = 0 ;
        List<DishFlavor> dishFlavors = dishDto.getFlavors();
        
        if(dishFlavors != null && dishFlavors.size() >0 ){
    
            for (DishFlavor dishFlavor : dishFlavors) {
                
                //设置这种口味属于哪一种菜品
                dishFlavor.setDishId(dishDto.getId());
                
                row2 += dishFlavorService.add(dishFlavor);
            }
            row = row >0 && row2 == dishFlavors.size() ? 1 :  0;
        }

        //原id
        Long redisId = dishRedis.getCategoryId();
        //更新后id
        Long newId = dishDto.getCategoryId();

        if (redisId == newId) {

            redisTemplate.delete("dish_"+redisId+"_1");
        } else {
            redisTemplate.delete("dish_"+redisId+"_1");
            redisTemplate.delete("dish_"+newId+"_1");
        }

        return row;
    }
    
    //分页查询菜品
    @Override
    public IPage<DishDto> findPage(PageParam pageParam) {
        //1. 先执行菜品表的分页查询【原来怎么写的，现在还怎么写！】
        IPage<Dish> p = new Page<>(pageParam.getPage() , pageParam.getPageSize());
        
        //1.1 设置查询条件
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();
        qw.like(pageParam.getName() != null , Dish::getName , pageParam.getName());
        
        //1.2 执行查询操作
        mapper.selectPage(p , qw);
        
        //2. 自己创建IPage<DishDto> ， 向上返回。
        IPage<DishDto> dishDtoIPage = new Page<>();
        
        //2.1 页面显示数据，只需要IPage对象里面的两个属性有值即可：  records  和  total
        //2.1.1  设置total数据
        dishDtoIPage.setTotal(p.getTotal());
        
        //2.1.2  设置records数据
        //2.1.2.1 遍历原先从数据库里面查询得到的那10条记录。
        List<DishDto> list = p.getRecords().stream().map(dish ->{
            
            //a. 创建DishDto对象。遍历一次，创建一个，遍历10次，创建10个
            DishDto dishDto  = new DishDto();
            
            //b. 把Dish的数据拷贝到这个dishDto里面。
            BeanUtils.copyProperties( dish,  dishDto);
            
            //c. 基本的数据已经拷贝好了之后，还要处理分类的名称。分类的名称，可以根据菜品的分类id去查询分类表得到数据
            dishDto.setCategoryName(categoryService.findById(dish.getCategoryId()).getName());
            
            //d. 还需要给这个菜品设置口味数据，以便在页面上点击修改的时候，到了add.html 能够回显 口味的数据
            dishDto.setFlavors(dishFlavorService.findByDishId(dish.getId()));
            
            //e. 返回dishDto 即表示后面Collectors.toList()产生的集合里面的元素就是这个dishDto
            return dishDto;
        
        }).collect(Collectors.toList());
    
        //设置集合数据
        dishDtoIPage.setRecords(list);
        return dishDtoIPage;
    }
    
   //添加菜品
    @Override
    public int add(DishDto dishDto) {

    
        //1. 往菜品表里面添加菜品数据
        int row = mapper.insert(dishDto);
        System.out.println("row = " + row);
        
        //2. 往口味表里面添加口味数据
        List<DishFlavor> flavorList = dishDto.getFlavors();
    
        //如果口味数据确实是有，那么就往口味表里面添加数据
        
        int row2 = 0 ;
        
        if(flavorList != null && flavorList.size() > 0){
            //2.1 遍历每一个口味数据
            for (DishFlavor dishFlavor : flavorList) {
                //2.2 . 给口味设置菜品的id值
                dishFlavor.setDishId(dishDto.getId());
                //2.3 添加口味数据到表里面
                row2 += dishFlavorService.add(dishFlavor);
            }
    
            //如果有口味的数据，那么判断菜品表的数据添加成功以及口味表的数据都成功，就返回1， 否则返回0
            row = row >0 && row2 == flavorList.size() ? 1 :0 ;
        }

        //菜品添加成功 就删除redis里该分类菜品
        String key = "dish_"+dishDto.getCategoryId()+"_1";
        redisTemplate.delete(key);

        // 如果没有口味数据，那么只需要返回菜品表的影响行数即可。
        return row  ;
    }
    
    //根据分类id来查询菜品表，查询这个分类在菜品表里面的总数
    @Override
    public int findCountByCategoryId(long categoryId) {
        
        //1. 创建条件对象
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();
        qw.eq(Dish::getCategoryId , categoryId);
        
        //执行查询  select count(*) from dish where category_id = categoryId;
        return mapper.selectCount(qw);
    }

    //根据菜品id 修改状态
    @Override
    public int updateStatus(Dish dish, Long dishId) {

       return mapper.updateById(dish);
    }

    //删除菜品数据
    @Override
    public int delete(List<Long> ids) {
        //设置查询条件
        LambdaQueryWrapper<Dish> lqw = new LambdaQueryWrapper<>();
        //查询菜品状态为启售的数据
        lqw.eq(Dish::getStatus, 1);
        lqw.in(Dish::getId, ids);

        //查询数量
        int count = mapper.selectCount(lqw);
        //判断启售状态数据 大于0则禁止删除
        if (count > 0) {
            throw new CustomException("菜品包含启售状态，禁止删除！");
        }

        int rows = mapper.deleteBatchIds(ids);

        //菜品删除成功 清空菜品缓存数据
        Set keys = redisTemplate.keys("dish_*");
        redisTemplate.delete(keys);

        return rows;
    }
}
